/*
--------------------------------------------------------------------------------
				Ak-Lib. 
			 Project       	: Ak-Lib
			 Group         	: Ak-Lib R&D Team
			 Author        	: Ocean.Wang
			 Create Date 	: 05-01-2010
--------------------------------------------------------------------------------
Code Name 	:  A.K 	~v~
Description	:  Yet Another Cross-Platform Lib.
Cautions    	:
--------------------------------------------------------------------------------
Change History:
Version		: 0.1
Building 		: 05/01/10
10-05.01 first draft, build, debug and test.
--------------------------------------------------------------------------------
*/

#include "ak_mem.h"


#undef _SMEM_DEBUG
/* Trace Lvl */
static 	int 	_gTraceLvl_SMem = TRACELVL_NORMAL;
/* Alignment */
#define _MPOOL_ALIGNMENT 		0X8


int 	SMem_SetTraceLvl(int lvl)
{
	int 	ret = -1;
	
	switch(lvl){
		case TRACELVL_FATAL:
		case TRACELVL_ERROR:
		case TRACELVL_WARNING:
		case TRACELVL_NORMAL:
		case TRACELVL_DEBUG:
		case TRACELVL_ALL:
			_gTraceLvl_SMem = lvl;
			ret = 0;
			break;
		default:
			break;
	}

	return ret;
}

int 	SMem_GetTraceLvl(void)
{
	return  _gTraceLvl_SMem;
}

/* -------------------------------------------------------------
** Mem Pool's Page Incr
*/
#define _MPAGE_INIT(pPage, vMem, vSize) \
	do{ \
		pPage 			= (_t_sysMPage *)(vMem);\
		(pPage)->size	= (vSize) - sizeof(_t_sysMPage);\
		BLIST_INIT(&((pPage)->itQue));\
	}while(0)
	
static 	int 		_MPool_PageIncr(_t_sysMPool * pPool, unsigned int pgSize, unsigned int pageCnt)
{
	unsigned char 	* pMem;
	_t_sysMPage		* pPage;
	_t_sysMHeap 	* pHeap;
	_t_blist 		* pQue;
	
	size_t 			total;
	unsigned int 	i, type;

	if(pageCnt > 0){
		/* Judge Mem Limit */
		type = pPool->type;
		switch(type){
			case MPOOL_T_SLAB_GN:
				total 	= pgSize;
				pageCnt	= 1;
				break;
			default:
				total = pgSize * pageCnt + sizeof(_t_sysMPage);
				break;
				
		}
  		pHeap = pPool->pHeap;
		if((pHeap->mAlloc + total)  <= pHeap->mLimit){
			pMem = (unsigned char *)SYS_ALIGN_ALLOC(_MPOOL_ALIGNMENT, total);
			if(pMem){
				/* ALK */
				SYS_ENTER_CS(&(pHeap->lock));
				pHeap->mAlloc += total;
				SYS_LEAVE_CS(&(pHeap->lock));

				/* CacheAble */
				switch(type){
					case MPOOL_T_SLAB_GN:
						break;
					default:
						_MPAGE_INIT(pPage, pMem, total);
						BLST_ADD2T(&(pPool->mAlk), &(pPage->node));
						pMem += sizeof(_t_sysMPage);
						break;
				}

				/* Page */
				pQue = &(pPool->pgAlk);
				for(i=0; i<pageCnt; i++, pMem += pgSize){
					_MPAGE_INIT(pPage, pMem, pgSize);
					BLST_ADD2T(pQue, &(pPage->node));
				}
				return 0;
			}
			else{
				pPool->bGC = 1;
			}
		}
		else{
			/* Here We Scan all the Pools to Trigger GC */
			for(i=0, pPool=pHeap->pools; i < pHeap->poolCnt; i++, pPool++){
				pPool->bGC = 1;
			}
		}
	}
	
	return -1;	
}


/* -------------------------------------------------------------
** Mem Pool's Page Alloc
*/
static 	_t_sysMPage * _MPool_PageAlloc(_t_sysMPool * pPool, unsigned int pgSize)
{
	_t_sysMPage 	* 	pPage;
	_t_blist 		* 	pQue;
	
	pPage = NULL;
	pQue = &(pPool->pgAlk);
	if(pQue->count > 0){
		pPage = (_t_sysMPage*)BLST_GET(pQue);
	}
	else{
		switch(pPool->type){
			case MPOOL_T_SLAB_GC:
				pPool->bGC = 1;
				break;
			default:
				break;
		}
		/* Let's Incr & Try Again */
		_MPool_PageIncr(pPool, pgSize, pPool->pgIncr);
		pPage = (_t_sysMPage *)BLST_GET(pQue);
	}

	return pPage;
}

#define MPOOL_PAGE_ALLOC(pPool, pPage, pgSize)	\
do{\
	pPage = NULL;\
	if(pPool){\
		SYS_ENTER_CS(&(pPool->lock));\
		pPage = _MPool_PageAlloc(pPool, pgSize);\
		SYS_LEAVE_CS(&(pPool->lock));\
	}\
}while(0)


/* -------------------------------------------------------------
** Mem Pool's Slab
*/
static 	int 	_MSlab_Judge(size_t * slabs, unsigned int slabCnt, size_t size) {
	int iterL, iterR, iterC;
	
	/* BiSearch */	
	iterL 	= 0;
	iterR 	= slabCnt - 1;
	
	do{
		iterC = (iterL + iterR)/2;
		if(slabs[iterC] <= size){
			if(slabs[iterC] == size)
				return iterC;
			
			iterL = iterC + 1;
		} else {
			iterR = iterC;
		}
	}while(iterL < iterR);
	
	return iterL;
}


/* -------------------------------------------------------------
** Mem Pool's Slot & Slots
*/
void	MHeap_Init(_t_sysMHeap * pHeap, size_t mLimit)
{
	SYS_INIT_CS(&(pHeap->lock));
	pHeap->mLimit	= mLimit * MPOOL_PAGESZ; 
	pHeap->mAlloc	= 0;
}

void	MHeap_InitEx(_t_sysMHeap * pHeap, size_t mLimit)
{
	SYS_INIT_CS(&(pHeap->lock));
	pHeap->mLimit	= mLimit + sizeof(_t_sysMPage); 
	pHeap->mAlloc	= 0;
}

void 	MPool_Init(_t_sysMPool * 	pPool, _t_sysMHeap * 	pHeap,
						size_t 			pgSz, 
						unsigned int 	itSzMax, 
						unsigned int 	pgIncr, 
						unsigned int 	pgInit,
						unsigned int 	type)
{
	if(pPool && (type <= MPOOL_T_SLAB_GN) && pHeap){
		/* Init the Que & Lock */
		BLIST_INIT(&(pPool->mAlk));
		BLIST_INIT(&(pPool->pgAlk));
		SYS_INIT_CS(&(pPool->lock));

		/* Init the Slabs & Slots & itSzMax*/
		MPOOL_SET_HEAP(pPool, pHeap);
		MPOOL_SET_SLOT(pPool, NULL);
		MPOOL_SET_SLAB(pPool, NULL);
		MPOOL_SET_SCNT(pPool, 0);
		MPOOL_SET_IMAX(pPool, itSzMax);

		/* Init the Cache & GC, PgSz, PgIncr */
		switch(type){
			case MPOOL_T_SLAB_GN:
				/* When Non-CacheAble, We Disable the Pre-Alloc */
				pPool->pgSz 	= pgSz;
				pPool->pgIncr	= 1;
				pgInit			= 0;
				break;
			
			default:
				pPool->pgSz 	= pgSz;
				pPool->pgIncr	= pgIncr;
				break;
		}
		pPool->type = type;
		pPool->bGC 	= 0;
		pPool->sCount= 0;
		_MPool_PageIncr(pPool, pgSz, pgInit);
	}
	return;
}

#define _MSLOT_SET(pSlot, vPool, vSId, vItSz) \
	do{\
		(pSlot)->pPool	= vPool;	\
		(pSlot)->sId	= vSId;		\
		(pSlot)->itSz 	= vItSz;	\
	}while(0);

void 	MSlot_Init(_t_sysMSlot * pSlot, _t_sysMPool * pPool, unsigned int sId, unsigned int itSz)
{
	if(pSlot && pPool){
		BLIST_INIT(&(pSlot->pgQue));
		BLIST_INIT(&(pSlot->itQue));
		SYS_INIT_CS(&(pSlot->lock));

		_MSLOT_SET(pSlot, pPool, sId, itSz);
		pSlot->itCntP	= (pPool->pgSz - sizeof(_t_sysMPage))/itSz;
		/* Now we Judge if the Slot is CacheAble */
		switch(pPool->type){
			case MPOOL_T_SLAB:
			case MPOOL_T_SLAB_GC:
				pSlot->pgSz = pPool->pgSz;
				break;
			default:
				pSlot->pgSz = (pSlot->itCntP * itSz) + sizeof(_t_sysMPage);
				break;
		}
	}
	
	return;
}

int 	MSlab_CalcCnt(unsigned int initSz, unsigned int maxSz, unsigned int * pCnt, unsigned int * pSz)
{
	unsigned int 	i, itSz;

	if(pCnt && pSz && (initSz > 0) && (maxSz > 0)){
		i 		= 0;
		itSz 	= initSz;
		do{
			if(i%2 == 1){
				itSz += (itSz >> 1); 
			}else{
				itSz = initSz << (i/2);
			}
			i++;
		}while(itSz < maxSz);
		/* the Min I is 1 */
		*pCnt 	= i;
		*pSz 	= itSz;
		return 0;
	}
	return -1;
}

int 	MSlab_Init(_t_sysMPool 	* 	pPool, 	_t_sysMSlot 	* slots, 
					size_t 	* 	slabs, 	
					int 		slabCnt, 
					int 		slabSz,
					int 		itAux){
    int 			i;
    long 			size;

	if(pPool && slots && slabs && (slabCnt > 0) && (slabSz > 0) ){
		/* We Init From the Slab */
		i 		= 0;
		size 	= slabSz;

		MPOOL_SET_SLAB(pPool, slabs);		
		MPOOL_SET_SLOT(pPool, slots);
		MPOOL_SET_SCNT(pPool, slabCnt);

		for(i=0; i<slabCnt; i++, slabs++, slots++){
	        /* 
	        	Make sure items are always n-byte aligned.
	        	Let's Use the Cumlate Average.
	        	*/
	  		if(i%2 == 1){
				size += (size >> 1); 
			}else{
				size = slabSz << (i/2);
			}
			/* Init the Slots && Slabs */
			*slabs = (size);
			MSlot_Init(slots, pPool, i, (unsigned int)(size + itAux));
			#if 1
	        SYS_TRACE(_gTraceLvl_SMem, TRACELVL_ERROR, "Slots Id: %3d ItemSz: %6u-%6u \n", 
	        			i, 
	        			size,
	        			*slabs);
			#endif
		}

		return 0;
	}
	
	return -1;
}


/* -------------------------------------------------------------
** Mem Pool's Slot IncrEx & AllocEx & FreeEx
*/
static	int 		_MSlot_Incr(_t_sysMPool * pPool, _t_sysMSlot * pSlot) {
	_t_sysMi	*	pItem;
	_t_sysMPage*	pPage;
	_t_blist	*	pQue;
	unsigned int	sId;
	long		i, count;
	
	MPOOL_PAGE_ALLOC(pPool, pPage, pPool->pgSz);
	if(pPage){
		/* Init Items */
		sId= pSlot->sId;
		count = pSlot->itCntP;

		switch(pPool->type){
			case MPOOL_T_SIMP:
				pItem = (_t_sysMi *)(pPage + 1);
				pQue= &(pSlot->itQue);
				for(i=0; i<count; i++){
					BLST_ADD2T(pQue, &(pItem->aNode));
					pItem = (_t_sysMi *)((unsigned char *)pItem + pSlot->itSz);
				}
				break;
			case MPOOL_T_SLAB:
				pItem = (_t_sysMi *)(pPage + 1);
				pQue  = &(pSlot->itQue);
				for(i=0; i<count; i++){
					pItem->alkId	= sId;
					pItem->jar		= pPage;
					BLST_ADD2H(pQue, &(pItem->aNode));
					pItem = (_t_sysMi *)((unsigned char *)pItem + pSlot->itSz);
				}
				break;

			default:
				pItem = (_t_sysMi *)(pPage + 1);
				pQue  = &(pPage->itQue);		BLIST_INIT(pQue);
				for(i=0; i<count; i++){
					pItem->alkId	= sId;
					pItem->jar		= pPage;
					BLST_ADD2H(pQue, &(pItem->aNode));
					pItem = (_t_sysMi *)((unsigned char *)pItem + pSlot->itSz);
				}
				break;
		}
		
		/* Only for Statistics */
		BLST_ADD2H(&(pSlot->pgQue), &(pPage->node));
		return 0;
	}

	return -1;
}


/* User Should Make Sure slabId is (0, SlabTbl] */
_t_sysMi *	MPool_AllocEx(_t_sysMPool * pPool, size_t size) {
	_t_sysMSlot	*pSlot;
	_t_sysMPage	*pPage;
	_t_sysMi		*pItem;
	int 			sId;

	pItem	= NULL;
	if(	pPool && (size <= pPool->itSzMax)
		#ifdef _SMEM_DEBUG
		&& ((pPool->type == MPOOL_T_SLAB_GC) || (pPool->type == MPOOL_T_SLAB_GN)) 
		#endif
	){
		sId 	= _MSlab_Judge(pPool->slabs, pPool->slabCnt, size);
#if 0
		SYS_TRACE(_gTraceLvl_SMem, TRACELVL_DEBUG, "Slot:%d Size: %lu\n", sId, size);
#endif
		if ((sId >=0) && (sId < pPool->slabCnt)){
			pSlot = (pPool->slots + sId);

			SYS_ENTER_CS(&(pSlot->lock));
				if (pSlot->pgQue.count == 0){
					_MSlot_Incr(pPool, pSlot);
				}

				if (pSlot->pgQue.count > 0){
					pPage = _O_PARENT(_t_sysMPage, node, (pSlot->pgQue.next));
					if(pPage->itQue.count == 0){
						/* Try Again */
						_MSlot_Incr(pPool, pSlot); 
						pPage = _O_PARENT(_t_sysMPage, node, (pSlot->pgQue.next)); 						
					}
					
					pItem = (_t_sysMi *)BLST_GET(&(pPage->itQue));
					if(pPage->itQue.count == 0){
						/* Move to Tail */
						if(pSlot->pgQue.prev!= (_t_bnode *)pPage){
							BLST_DEL(&(pSlot->pgQue), &(pPage->node));
							BLST_ADD2T(&(pSlot->pgQue), &(pPage->node));
						}
					}
				}
			SYS_LEAVE_CS(&(pSlot->lock));
		}
	}
	
	return pItem;
}


int 	MPool_FreeEx(_t_sysMPool * pPool, _t_sysMi * pItem) {
	_t_sysMSlot		*pSlot;
	_t_sysMPage		*pPage;
	unsigned char		*pBeg, *pEnd;
	unsigned int 		sId;

	if(	pPool && pItem 
		#ifdef _SMEM_DEBUG
		&& ((pPool->type == MPOOL_T_SLAB_GC) || (pPool->type == MPOOL_T_SLAB_GN)) 
		#endif
	){
		sId = pItem->alkId;
		if(sId < pPool->slabCnt){
			pSlot = (pPool->slots + sId);
			
			SYS_ENTER_CS(&(pSlot->lock));
				pPage = (_t_sysMPage *)(pItem->jar);
				if(pPage){
					/* Let's Check */
					pBeg = (unsigned char *)(pPage + 1);
					pEnd = (unsigned char *)(pBeg  + pPage->size);
					if((pBeg <=  (unsigned char *)pItem) && 
						(pEnd >= ((unsigned char *)pItem + pSlot->itSz))){
						BLST_ADD2H(&(pPage->itQue), &(pItem->aNode));
						
						/* Move to Head */
						if(pSlot->pgQue.next != (_t_bnode *)pPage){
							BLST_BUBBLE2H(&(pSlot->pgQue), &(pPage->node));
						}
					}
					else{
						/* Exception */
						SYS_TRACE(_gTraceLvl_SMem, TRACELVL_ERROR, "Pool:%p Item:%p Beg:%p Eng:%p Sid:%d\n", 
									pPool, pItem, pBeg, pEnd, sId);
					}
				}
			SYS_LEAVE_CS(&(pSlot->lock));
			return 0;
		}
		
	}
	return -1;
}


/* -------------------------------------------------------------
** Slot's GC
*/
static 	int 	_MSlot_GC(_t_sysMPool * pPool, _t_sysMSlot * pSlot, long gcCnt)
{
	_t_blist    	*pQue;
	_t_sysMPage 	*pPage, *pNext;
	_t_sysMHeap 	*pHeap;
	_t_blist 		recycle;
	unsigned int 	itemCnt;
	long 			i, count;
	size_t 			total;
	
	BLIST_INIT(&recycle);
	itemCnt	= pSlot->itCntP;
	
	SYS_ENTER_CS(&(pSlot->lock));
	/* Go through the Jar Que */
	pQue 	= &(pSlot->pgQue);
	count	= pQue->count;
	pPage 	= _O_PARENT(_t_sysMPage, node, (pQue->next));
	for(i=0; i<count; i++, pPage=pNext){
		pNext = _O_PARENT(_t_sysMPage, node, (pPage->node.next));
		if(pPage->itQue.count == itemCnt){
			/* Let's Free back to Pool */
			BLST_DEL(pQue, &(pPage->node));
			BLST_ADD2T(&recycle, &(pPage->node));
			if(recycle.count >= gcCnt){
				break;
			}
		}
	}
	SYS_LEAVE_CS(&(pSlot->lock));
	
	/* Recycle Back to Pool */
	total = 0;
	count = recycle.count;
	if(count > 0){
		if(pPool->type == MPOOL_T_SLAB_GC){
			SYS_ENTER_CS(&(pPool->lock));
			BLST_CAT(&(pPool->pgAlk), &recycle);
			SYS_LEAVE_CS(&(pPool->lock));
		}
		else{
			/* Recycle Back to System, Only Big Chunks Need it. */
			for(i=0; i<count; i++){
				pPage = _O_PARENT(_t_sysMPage, node, (BLST_GET(&recycle)));
				total += (pPage->size + sizeof(_t_sysMPage));
				SYS_ALIGN_FREE(pPage);
			}
			/* Update the Mem's Alloc */
			pHeap = pPool->pHeap;
			SYS_ENTER_CS(&(pHeap->lock));
			pHeap->mAlloc -= total;
			SYS_LEAVE_CS(&(pHeap->lock));
		}
	}

	return count;			
}

int 	MPool_GC(_t_sysMPool * pPool, unsigned int gcCnt)
{
	_t_sysMSlot 	*	pSlot;
	int 			i;
	unsigned int	count;

	#ifdef _SMEM_DEBUG
	if(	(pPool->type == MPOOL_T_SLAB_GC) || 
		(pPool->type == MPOOL_T_SLAB_GN) )
	#endif
	{
			
		i = pPool->slabCnt - 1;
		pSlot = &(pPool->slots[i]);
		count = 0;
		for(; i>=0; i--, pSlot--){
			count += _MSlot_GC(pPool, pSlot, gcCnt-count);
			if(count >= gcCnt)
				break;
		}
		SYS_ENTER_CS(&(pPool->lock));
		pPool->bGC = 0;
		SYS_LEAVE_CS(&(pPool->lock));
	}

	return 0;
}


/* -------------------------------------------------------------
** Mem Pool's Slot Incr & Alloc & Free
*/


/* User Should Make Sure slabId is (0, SlabTbl] */
_t_sysMi *	MPool_Alloc(_t_sysMPool * pPool, size_t size) {
	_t_sysMi	*	pItem;
    _t_sysMSlot*	pSlot;
	int 		sId;
	
	pItem 	= NULL;
	if(pPool && (size <= pPool->itSzMax)
		#ifdef _SMEM_DEBUG
		&& (pPool->type == MPOOL_T_SLAB) 
		#endif
	){
		sId 	= _MSlab_Judge(pPool->slabs, pPool->slabCnt, size);
#if 0
		SYS_TRACE(gTraceLvl_Mem, TRACELVL_WARNING,  "Slot:%d Size: %lu\n", sId, size);
#endif
		if ((sId >=0) && (sId < pPool->slabCnt)){
		    pSlot = (pPool->slots + sId);

			SYS_ENTER_CS(&(pSlot->lock));
			    if (pSlot->itQue.count == 0){
					_MSlot_Incr(pPool, pSlot);
			    }
				pItem = (_t_sysMi *)BLST_GET(&(pSlot->itQue));
			SYS_LEAVE_CS(&(pSlot->lock));
		}
	}
	
	return pItem;
}


int 	MPool_Free(_t_sysMPool * pPool, _t_sysMi * pItem) {
    _t_sysMSlot*	pSlot;
	unsigned int 	sId;

	if(pPool && pItem 
		#ifdef _SMEM_DEBUG
		&& (pPool->type == MPOOL_T_SLAB) 
		#endif
	){
		sId = pItem->alkId;
		if(sId < pPool->slabCnt){
		    pSlot = (pPool->slots + sId);
			
			SYS_ENTER_CS(&(pSlot->lock));
				BLST_ADD2H(&(pSlot->itQue), &(pItem->aNode));
			SYS_LEAVE_CS(&(pSlot->lock));
			return 0;
		}
	}

	return -1;
}

int 	MPool_Pre(_t_sysMPool * pPool, unsigned int sId, unsigned int preCnt){
	_t_sysMSlot	*	pSlot;
	int 			i, ret;

	ret = -1;
	if(pPool && (preCnt > 0) && (sId < pPool->slabCnt)
		#ifdef _SMEM_DEBUG
		 &&
		(	(pPool->type == MPOOL_T_SLAB) ||
			(pPool->type == MPOOL_T_SLAB_GC) ||
			(pPool->type == MPOOL_T_SLAB_GN))
		#endif
	){
		pSlot 	= pPool->slots + sId;

		SYS_ENTER_CS(&(pSlot->lock));
		for(i=0; i<preCnt; i++){
			if((ret = _MSlot_Incr(pPool, pSlot)) == -1){
				break;
			}
		}
		SYS_LEAVE_CS(&(pSlot->lock));
	}
	return ret;
}

/* -------------------------------------------------------------
** Mem Pool's Slot Simple Alloc & Free
*/
int 	MPool_PreSx(_t_sysMPool * pPool, unsigned int preCnt){
	_t_sysMSlot	*pSlot;
	int 			i, ret;

	ret = -1;
	if(pPool && (preCnt > 0)
		#ifdef _SMEM_DEBUG
		&& (pPool->type == MPOOL_T_SIMP)
		#endif
	){
		pSlot 	= pPool->slots;

		SYS_ENTER_CS(&(pSlot->lock));
		for(i=0; i<preCnt; i++){
			if((ret = _MSlot_Incr(pPool, pSlot)) == -1){
				break;
			}
		}
		SYS_LEAVE_CS(&(pSlot->lock));
	}
	return ret;
}


int 	MPool_ExecSi(_t_sysMPool * pPool, _t_cbentry * pCbEntry)
{
	_t_sysMSlot	*pSlot;
	_t_blist 	*pQue;
	_t_bnode	*pItem;
	long 		i, count;

	pItem	= NULL;
	if(pPool && pCbEntry && (pCbEntry->cbProc)
	#ifdef _SMEM_DEBUG
		&& (pPool->type == MPOOL_T_SIMP)
	#endif
	){
		pSlot 	= pPool->slots;

		SYS_ENTER_CS(&(pSlot->lock));
			if (pSlot->pgQue.count == 0){
				_MSlot_Incr(pPool, pSlot);
			}
			pQue  = &(pSlot->itQue);
			count = pQue->count;
			for(i=0, pItem=pQue->next; 
				i<count; 
				i++, pItem=pItem->next){
				pCbEntry->cbProc(pCbEntry->pArg, 
								pCbEntry->lArg,
								pItem, i);
			}
		SYS_LEAVE_CS(&(pSlot->lock));
	}
	
	return 0;
	
}

void *	MPool_AllocSi(_t_sysMPool * pPool) {
	_t_sysMSlot	*pSlot;
	_t_bnode	*pItem;

	pItem	= NULL;
	if(pPool 
		#ifdef _SMEM_DEBUG
		&& (pPool->type == MPOOL_T_SIMP)
		#endif
	){
		pSlot 	= pPool->slots;

		SYS_ENTER_CS(&(pSlot->lock));
			if (pSlot->itQue.count == 0){
				_MSlot_Incr(pPool, pSlot);
			}
			pItem = BLST_GET(&(pSlot->itQue));
			if(pItem){
				pPool->sCount += 1;
			}
		SYS_LEAVE_CS(&(pSlot->lock));
	}
	
	return (void *)pItem;
}


int 	MPool_FreeSi(_t_sysMPool * pPool, void * pItem) {
	_t_sysMSlot		*pSlot;

	if(pPool && pItem 
		#ifdef _SMEM_DEBUG
		&& (pPool->type == MPOOL_T_SIMP)
		#endif
	){
		pSlot = pPool->slots;
		SYS_ENTER_CS(&(pSlot->lock));
			BLST_ADD2H(&(pSlot->itQue), (_t_bnode *)(pItem));
			pPool->sCount -= 1;
		SYS_LEAVE_CS(&(pSlot->lock));
		return 0;
	}
	return -1;
}

int 	MPool_FreeSi2(_t_sysMPool * pPool, void * pItem) {
	_t_sysMSlot		*pSlot;

	if(pPool && pItem 
		#ifdef _SMEM_DEBUG
		&& (pPool->type == MPOOL_T_SIMP)
		#endif
	){
		pSlot = pPool->slots;
		SYS_ENTER_CS(&(pSlot->lock));
			BLST_ADD2T(&(pSlot->itQue), (_t_bnode *)(pItem));
			pPool->sCount -= 1;
		SYS_LEAVE_CS(&(pSlot->lock));
		return 0;
	}
	return -1;
}

int 	MPool_AllocNi(_t_sysMPool * pPool, _t_blist * opQue, int count){
	_t_sysMSlot	*pSlot;
	int 		ret;

	ret = -1;
	if(pPool && opQue && (count > 0)
		#ifdef _SMEM_DEBUG
		&&	(pPool->type == MPOOL_T_SIMP)
		#endif
	){
		pSlot	= pPool->slots;
		SYS_ENTER_CS(&(pSlot->lock));
			if(pSlot->itQue.count <= count){
				_MSlot_Incr(pPool, pSlot);
			}
			if(pSlot->itQue.count > count){
				ret = BLST_GETN(&(pSlot->itQue), opQue, count);
				if(ret == 0){
					pPool->sCount += count;
				}
			}
		SYS_LEAVE_CS(&(pSlot->lock));
	}
	
	return ret;
}

int 	MPool_FreeNi(_t_sysMPool * pPool, _t_blist * opQue){
	_t_sysMSlot	*pSlot;
	int 	ret;

	ret = -1;
	if(pPool && opQue && (opQue->count > 0)
		#ifdef _SMEM_DEBUG
		&& (pPool->type == MPOOL_T_SIMP) 
		#endif
	){
		pSlot	= pPool->slots;
		SYS_ENTER_CS(&(pSlot->lock));
			ret = opQue->count;
			BLST_JOIN(&(pSlot->itQue), opQue);	
			pPool->sCount -= ret;
		SYS_LEAVE_CS(&(pSlot->lock));
		ret = 0;
	}
	return ret;
}


/* -------------------------------------------------------------
** Mem Pool's Dump
*/
#define 	_MALK_DUMP(jter, outBuf, bufLen, length, pPage) \
	do{\
		if((jter%4)==3){\
			length += SYS_SNPRINTF(outBuf + length, bufLen -length, "\t[M:%02d](Sz:0x%lx)\n", \
						jter,	(unsigned long)((pPage)->size));\
		}else{\
			length += SYS_SNPRINTF(outBuf + length, bufLen -length, "\t[M:%02d](Sz:0x%lx)", \
						jter,	(unsigned long)((pPage)->size));\
		}\
	}while(0)

#define 	_PALK_DUMP(jter, outBuf, bufLen, length, pPage) \
	do{\
		if((jter%4)==3){\
			length += SYS_SNPRINTF(outBuf + length, bufLen -length, "\t[P:%02d](Sz:0x%lx PI:%ld)\n", \
						jter, 	(unsigned long)((pPage)->size), (pPage)->itQue.count);\
		}else{\
			length += SYS_SNPRINTF(outBuf + length, bufLen -length, "\t[P:%02d](Sz:0x%lx PI:%ld)", \
						jter, 	(unsigned long)((pPage)->size), (pPage)->itQue.count);\
		}\
	}while(0)
	
int 	MPool_Dump(_t_sysMPool  * pPool, char * outBuf, int bufLen)
{
	_t_sysMSlot * pSlot;
	_t_sysMHeap * pHeap;
	_t_sysMPage * pPage;
	size_t 		 * pSlab;
	_t_blist 	 * pQue;
	
	int 		i, j, len;

	len = 0;
	/* Pool Info */
	pHeap = pPool->pHeap;
	len += SYS_SNPRINTF(outBuf + len, bufLen -len, "(L:0x%lx - A:0x%lx - M:%ld - P:%ld)[Type:0x%08x GC:%d Incr:%u PgSz:0x%08x Slab:%u Max:0x%x]\n",
		(unsigned long)(pHeap->mLimit), 		(unsigned long)(pHeap->mAlloc), 
		pPool->mAlk.count,	pPool->pgAlk.count,
		pPool->type,		pPool->bGC,			
		pPool->pgIncr,		pPool->pgSz,
		pPool->slabCnt, 	pPool->itSzMax);

	/* Go through the pPool's */
	SYS_ENTER_CS(&(pPool->lock));
	/* Mem Alk */
	pQue = &(pPool->mAlk);
	for(j=0, pPage=(_t_sysMPage*)(pQue->next); 		
		j<pQue->count; 
		j++, pPage=(_t_sysMPage*)(pPage->node.next)){
		_MALK_DUMP(j, outBuf, bufLen, len, pPage);
	}
	len += SYS_SNPRINTF(outBuf + len, bufLen - len, "\n");

	SYS_LEAVE_CS(&(pPool->lock));

	/* Go through the Slots */
	switch(pPool->type){
		case MPOOL_T_SIMP:
			pSlot = pPool->slots;
			/* Go through the Slot */
			SYS_ENTER_CS(&(pSlot->lock));
			len += SYS_SNPRINTF(outBuf + len, bufLen -len, "SI[Id:%-2d](PgQ:%-8ld ItQ:%-8ld ItSz:0x%08x ICntP:%-8u PgSz:0x%08x)\n", 
							pSlot->sId, 
							pSlot->pgQue.count, pSlot->itQue.count,
							pSlot->itSz,		pSlot->itCntP,		pSlot->pgSz);
			
			SYS_LEAVE_CS(&(pSlot->lock));
			break;

		case MPOOL_T_SLAB:
			for(i=0, pSlot=pPool->slots, pSlab=pPool->slabs; i<pPool->slabCnt; 
				i++, pSlot++, pSlab++){
				SYS_ENTER_CS(&(pSlot->lock));
				len += SYS_SNPRINTF(outBuf + len, bufLen -len, "SL[%02d - Id:%-2d Slab:%-8lu](PgQ:%-8ld ItQ:%-8ld ItSz:0x%08x ICntP:%-8u PgSz:0x%08x)\n", 
							i, pSlot->sId, 		(unsigned long)(*pSlab), 
							pSlot->pgQue.count,	pSlot->itQue.count,
							pSlot->itSz, 		pSlot->itCntP, 		pSlot->pgSz);

				SYS_LEAVE_CS(&(pSlot->lock));
			}
			break;

		default:
			for(i=0, pSlot=pPool->slots, pSlab=pPool->slabs; i<pPool->slabCnt; 
				i++, pSlot++, pSlab++){
				/* Go through the Slot */
				SYS_ENTER_CS(&(pSlot->lock));
				len += SYS_SNPRINTF(outBuf + len, bufLen -len, "GC[%02d - Id:%-2d Slab:%-8lu](PgQ:%-8ld ItQ:%-8ld ItSz:0x%08x ICntP:%-8u PgSz:0x%08x)\n", 
							i, pSlot->sId, 		(unsigned long)(*pSlab), 
							pSlot->pgQue.count, pSlot->itQue.count,
							pSlot->itSz,		pSlot->itCntP,		pSlot->pgSz);
				
				pQue = &(pSlot->pgQue);
				for(j=0, pPage=(_t_sysMPage*)(pQue->next); 	j<pQue->count; 
					j++, pPage=(_t_sysMPage*)(pPage->node.next)){
						_PALK_DUMP(j, outBuf, bufLen, len, pPage);
				}
				len += SYS_SNPRINTF(outBuf + len, bufLen - len, "\n");
				SYS_LEAVE_CS(&(pSlot->lock));
			}
			break;
	}

	return len;
}


